/*	Copyright 2008 Jacquemin Valentin

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
	
	@author pollux
 */
package org.poxd.model;

import java.util.Map;
import java.util.Vector;

import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

import org.apache.log4j.Logger;

/**
 * @author pollux
 * 
 */
public class CategoriesModel implements TreeModel {
	private static final long serialVersionUID = 1L;
	private static final Logger log = Logger.getLogger(CategoriesModel.class);
	private Vector<TreeModelListener> treeModelListeners = new Vector<TreeModelListener>();
	private Map<String, Category> categories;
	private final Object root = new Object();

	public CategoriesModel() {
		this(null);
	}

	public CategoriesModel(Map<String, Category> categories) {
		this.categories = categories;
	}

	public void setCategories(Map<String, Category> categories) {
		this.categories = null;
		if (categories != null && !categories.isEmpty()) {
			this.categories = categories;
			log.debug("KEYS");
			if (log.isDebugEnabled()) {
				for (String key : categories.keySet()) {
					log.debug(key);
					Category cat = categories.get(key);
					log.debug("Nb snippets:" + cat.getSnippets() == null ? 0
							: cat.getSnippets().size());
				}
			}
		}
		fireTreeStructureChanged();
	}

	/**
	 * The only event raised by this model is TreeStructureChanged with the root
	 * as path, i.e. the whole tree has changed.
	 */
	protected void fireTreeStructureChanged() {
		TreeModelEvent e = new TreeModelEvent(this, new Object[] { root });
		for (TreeModelListener tml : treeModelListeners) {
			tml.treeStructureChanged(e);
		}
	}

	public void addTreeModelListener(TreeModelListener l) {
		treeModelListeners.addElement(l);
	}

	public Object getChild(Object parent, int index) {
		log.debug("PARENT == ROOT " + (parent == root));
		log.debug("PARENT IS A CATEGORY " + (parent instanceof Category));
		if (parent instanceof Category) {
			Category c = (Category) parent;
			return c.getSnippets().get(index);
		} else if (parent == root) {
			if (categories != null) {
				// number of elements that are in the Category that represents
				// none
				// category
				int size = categories.get(Category.NULL_CATEGORY).getSnippets()
						.size();
				if (index < size) {
					return categories.get(Category.NULL_CATEGORY).getSnippets()
							.get(index);
				} else {
					if (index != 0 || (size -1) >= 0 ||(index - (size -1)) >= 0) {
						index -= (size - 1);
						for (String key : categories.keySet()) {
							if (index-- == 0) {
								return categories.get(key);
							}
						}
					}
				}
			}
		}
		return null;
	}

	public int getChildCount(Object parent) {
		if (parent instanceof Category) {
			Category c = (Category) parent;
			return c.getSnippets().size();
		} else if (parent == root) {
			if (categories != null) {
				int nbNoCategorized = categories.get(Category.NULL_CATEGORY)
						.getSnippets().size();
				int nbCategories = categories.keySet().size() - 1;
				log.debug("ChildCount for root="
						+ (nbNoCategorized + nbCategories));
				return nbNoCategorized + nbCategories;
			}
		}
		return 0;
	}

	public int getIndexOfChild(Object parent, Object child) {
		if (child == null || parent == null)
			return -1;
		if (parent == root) {
			if (categories != null) {
				if (categories.get(Category.NULL_CATEGORY).getSnippets()
						.contains(child)) {
					return categories.get(Category.NULL_CATEGORY).getSnippets()
							.indexOf(child);
				} else {
					int index = 0;
					for (Category cat : categories.values()) {
						index++;
						if (cat == child)
							return index;
					}
				}
			}
		} else if (parent instanceof Category) {
			Category cat = (Category) parent;
			if (cat.getSnippets().contains(child)) {
				return cat.getSnippets().indexOf(child);
			}
		}
		return -1;
	}

	public Object getRoot() {
		return root;
	}

	public boolean isLeaf(Object node) {
		if (node instanceof Category)
			return false;
		if (node instanceof Snippet)
			return true;
		return false;
	}

	public void removeTreeModelListener(TreeModelListener l) {
		treeModelListeners.removeElement(l);
	}

	public void valueForPathChanged(TreePath path, Object newValue) {
		// never called
	}

	public Category getSnippetCategory(Snippet s) {
		Category ret = null;
		for (Category cat : categories.values()) {
			if (cat.getSnippets().contains(s)) {
				ret = cat;
				break;
			}
		}
		return ret;
	}
	
	public Category getFirstCategory(){
		return categories.values().iterator().next();
	}
}
